home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1993 / MacHack 1993.toast / MacHack™ 1987-1992 / MacHack™ '90 / Source Code ƒ / MPW C ƒ / BIOMORƒ / Biomorph.c next >
Encoding:
C/C++ Source or Header  |  1990-06-14  |  7.5 KB  |  395 lines  |  [TEXT/MPS ]

  1. /*
  2.     Biomorphs - by John Jeppson.
  3.     
  4.     This source code is in the public domain.
  5.     Written in MPW C.
  6.     
  7.     This program is an MPW Tool which implements Biomorphs as
  8.     described in "Computer Recreations" by A.K.Dewdney in
  9.     Scientific American, July 1989.  
  10.  
  11.     From the MPW Worksheet execute:
  12.     
  13.         Biomorph  c.real c.imag   top  left  bottom  right
  14.     
  15.     where "c" is the required complex constant and "top", etc.
  16.     are the components of the target rectangle on the complex
  17.     plane. Our complex plane has the imaginary component
  18.     increasing downward in the usual Macintosh fashion.
  19.     
  20.     After the biomorph is drawn you will hear a SysBeep.  You
  21.     may interrupt a partially completed drawing by clicking the
  22.     mouse or pressing any key. You may not see any immediate
  23.     effect, but the drawing will soon terminate with a double
  24.     SysBeep at the end of the current vertical pass.
  25.  
  26.     You may print the completed biomorph by pressing "p".
  27.  
  28.     Return to the shell with the close box.
  29.  
  30.     The iterated generating function is supplied in the
  31.     program function "generator".  The tool must be recompiled
  32.     to install a different generator.
  33.     
  34.     It is easiest to use the functions available in <Complex.h>.
  35.     For example:
  36.     
  37.             complex  generator(complex z)   //  z = z^3 + c 
  38.             {
  39.                 return    ( cadd (cxpwri(z, 3), c) );
  40.             }
  41.     
  42.     These built-in complex functions, however, are quite slow,
  43.     so you may want to use your own formulae whenever possible,
  44.     as is done in the program below.
  45.             
  46.  
  47.  
  48.     The article in Scientific American suggests:
  49.     
  50.         c:             0.5 + 0.0i
  51.         bounds:        -1.5, -1.5, 1.5, 1.5
  52.         generator:    z = z^3 + c
  53.         
  54.               NOTE:  The program below uses this generator;
  55.                   from the MPW shell execute:
  56.     
  57.                 Biomorph  0.5  0.0   -1.5  -1.5  1.5  1.5
  58.  
  59.  
  60.  
  61.     The spiky radiolarian actually illustrated in the Scientific
  62.       American article is created by:
  63.  
  64.         c:             0.2 + 0.8i
  65.         bounds:        -10.0, -10.0, 10.0, 10.0
  66.         generator:    z = z^3 + c
  67.         
  68.  
  69.     Try also:    
  70.  
  71.         c:             0.2 + 0.8i
  72.         bounds:        -1.2, -1.2, 1.2, 1.2
  73.         generator:    z = z^5 + c
  74.                  use:  cadd (cxpwri(z, 5), c)
  75.  
  76.  
  77.     
  78.         c:             0.5 + 0.8i
  79.         bounds:        3.15, 2.2, 4.35, 3.4
  80.         generator:    z = sin(z) + z^2 + c
  81.                  use:  cadd (cadd (csin(z), csquare(z)), c)
  82. */
  83.  
  84. #include <Types.h>
  85. #include <Windows.h>
  86. #include <Memory.h>
  87. #include <Printing.h>
  88. #include <Fonts.h>
  89. #include <Resources.h>
  90. #include <OSUtils.h>
  91. #include <Math.h>
  92. #include <Complex.h>
  93. #include <StdLib.h>
  94.  
  95.  
  96. #define stepsX            100
  97. #define stepsY            100
  98.  
  99. #define windowTop        40
  100. #define windowLeft        4
  101. #define windowHeight    ( stepsY + 40 )
  102. #define windowWidth        ( stepsX + 40 )
  103. #define windowTitle        "\pBiomorphs"
  104.  
  105. #define nil                0L
  106.  
  107.  
  108. typedef struct
  109. {
  110.     extended     top,left,bottom,right;
  111. } cRect;
  112.  
  113.  
  114. /**** globals ****/
  115.  
  116.     WindowPtr    display;
  117.     complex        c;
  118.     cRect        target;
  119.     extended    incX, incY;
  120.     short        x0, y0;
  121.     Boolean        alreadyDrawn;
  122.     BitMap        offScreen;
  123.  
  124.  
  125.  
  126. complex  generator(complex z)
  127.     //   z = z^3 + c
  128.     //   (a+bi)^3 = a(a^2 - 3b^2) + b(3a^2 - b^2)i
  129. {
  130.     complex n;
  131.     
  132.     n.re = z.re * ((z.re * z.re) - (3 * z.im * z.im)) + c.re;
  133.     n.im = z.im * ((3 * z.re * z.re) - (z.im * z.im)) + c.im;
  134.     
  135.     return n;
  136. }
  137.  
  138. /*   //  equivalent alternative function--  easier, but slower.
  139. {
  140.     return    ( cadd (cxpwri(z, 3), c) );
  141. }
  142. */
  143.  
  144.  
  145. void plot (short x, short y, Boolean isBlack)
  146. {
  147.     if ( isBlack )
  148.     {
  149.         MoveTo (x0 + x, y0 + y);
  150.         Line (0,0);
  151.     }
  152. }
  153.  
  154.  
  155. complex  computeZzero(short j, short k)
  156. {
  157.     complex n;
  158.     
  159.     n.re = target.left + (incX * j);
  160.     n.im = target.top  + (incY * k);
  161.     return n;
  162. }
  163.  
  164.  
  165. extended modSq(complex z)
  166. {
  167.     return ( (z.re * z.re)  +  (z.im * z.im) );
  168. }
  169.  
  170.  
  171. void drawContents(WindowPtr w)
  172. {
  173.     short        j, k, n;
  174.     complex        z;
  175.     EventRecord    evt;
  176.     
  177.  
  178.     EraseRect(&(w->portRect));
  179.  
  180.     if ( alreadyDrawn )
  181.         CopyBits (&offScreen, &(display->portBits),
  182.                     &(offScreen.bounds), &(offScreen.bounds),
  183.                         srcCopy, nil);
  184.  
  185.     else
  186.     {
  187.         while ( GetNextEvent(mDownMask + keyDownMask, &evt) )
  188.             {};  /* dump event queue */
  189.             
  190.         PenNormal();
  191.         for ( j = 0; j < stepsX; ++j )
  192.         {
  193.             if ( EventAvail(mDownMask + keyDownMask, &evt) )
  194.                 break;
  195.             for ( k = 0; k < stepsY; ++k )
  196.             {
  197.                 z = computeZzero(j,k);
  198.                 for ( n = 0; n < 10; ++n )
  199.                 {
  200.                     z = generator(z);
  201.                     if ( (fabs(z.re) > 10.0)   ||
  202.                          (fabs(z.im) > 10.0)   ||
  203.                          (modSq(z)   > 100.0)   )
  204.                         break;
  205.                 }
  206.                 plot (j, k, ((fabs(z.re) < 10) || (fabs(z.im) < 10)) );
  207.             }
  208.         }
  209.         alreadyDrawn = true;
  210.         CopyBits (&(display->portBits), &offScreen,
  211.                     &(offScreen.bounds), &(offScreen.bounds),
  212.                         srcCopy, nil);
  213.         SysBeep(1);
  214.     }
  215. }
  216.  
  217.  
  218. /**** generic tool stuff ****/
  219.  
  220.  
  221. void doUpdate(WindowPtr w)
  222. {
  223.     GrafPtr    savePort;
  224.     
  225.     GetPort(&savePort);
  226.     SetPort(w);
  227.     ClipRect(&(w->portRect));
  228.     BeginUpdate(w);
  229.         drawContents(w);
  230.     EndUpdate(w);
  231.     SetPort(savePort);
  232. }
  233.  
  234.  
  235. void makeOffScreen()   /* set up offscreen bitmap to store image */
  236. {
  237.     Size        sizeOfOff;
  238.     short        offRowBytes;
  239.  
  240.     offRowBytes = (((windowWidth - 1) / 16) + 1) * 2;
  241.     sizeOfOff = windowHeight * offRowBytes;
  242.     
  243.     offScreen.baseAddr = (QDPtr) NewPtr(sizeOfOff);
  244.     offScreen.rowBytes = offRowBytes;
  245.     SetRect(&(offScreen.bounds), 0, 0, windowWidth, windowHeight);
  246. }
  247.  
  248.  
  249. void makeWindow()
  250. {
  251.     Rect    bounds;
  252.  
  253.     SetRect(&bounds, windowLeft, windowTop, windowLeft + windowWidth, windowTop + windowHeight);
  254.     display = NewWindow(nil, &bounds, windowTitle, true, noGrowDocProc, (WindowPtr) -1, true, 0L);
  255. }
  256.  
  257.  
  258. void printWindow()
  259. {
  260.     TPPrPort    pport;
  261.     THPrint        hPrint;
  262.     TPrStatus    PrStatus;
  263.     GrafPtr        oldPort;  
  264.     Boolean     notCancelled = true;
  265.     Boolean        drop;
  266.  
  267.     GetPort (&oldPort);
  268.     PrOpen();
  269.  
  270.     SetFractEnable(true);
  271.     SetFScaleDisable(true);
  272.  
  273.     hPrint = (THPrint) NewHandle(sizeof(TPrint));
  274.     if (ResError())
  275.     {
  276.         printf ("Printing Error %d\n", ResError());
  277.         SysBeep(1);
  278.         PrClose();
  279.         return;
  280.     }
  281.     
  282.     drop = PrValidate(hPrint);
  283.     notCancelled = PrJobDialog (hPrint);
  284.         
  285.     if (notCancelled)
  286.     {
  287.         pport = PrOpenDoc(hPrint, nil, nil);
  288.         if ( PrError() == noErr )
  289.         {
  290.             PrOpenPage(pport, nil);
  291.             if (PrError()==noErr)
  292.                 CopyBits (&offScreen, &(pport->gPort.portBits),
  293.                     &(offScreen.bounds), &(offScreen.bounds),
  294.                         srcCopy, nil);
  295.             PrClosePage(pport);
  296.         }
  297.         PrCloseDoc(pport);
  298.     }
  299.     if ( ((**hPrint).prJob.bJDocLoop == bSpoolLoop)
  300.              && (PrError() == noErr) )
  301.         PrPicFile (hPrint, nil, nil, nil, &PrStatus);
  302.         
  303.     SetFractEnable(false);
  304.     SetFScaleDisable(false);
  305.  
  306.     PrClose();
  307.  
  308.     SetPort (oldPort);
  309. }
  310.  
  311.  
  312. void mainLoop()
  313. {
  314.     Boolean            done = false;
  315.     EventRecord        theEvent;
  316.     WindowPtr        whichWindow;
  317.     short            part;
  318.     
  319.     while ( !done )
  320.     {
  321.         if ( GetNextEvent(everyEvent, &theEvent) )
  322.         {
  323.             switch ( theEvent.what )
  324.             {
  325.                 case updateEvt:
  326.                     doUpdate(display);
  327.                     break;
  328.  
  329.                 case mouseDown:
  330.                     part = FindWindow(theEvent.where, &whichWindow);
  331.                     if ( (whichWindow == display) && (part == inGoAway) )
  332.                         done = true;
  333.                     else
  334.                         SysBeep(1);
  335.                     break;
  336.  
  337.                 case keyDown:
  338.                     if ( 'p' == (theEvent.message & charCodeMask) )
  339.                         printWindow();
  340.                     else
  341.                         SysBeep(1);
  342.                     break;
  343.             }
  344.         }
  345.     }
  346. }
  347.  
  348.  
  349. void cleanUp()
  350. {
  351.     DisposeWindow(display);
  352.     DisposPtr((Ptr) offScreen.baseAddr);
  353. }
  354.  
  355.  
  356. int main (
  357.     int  argc,            /* number of arguments */
  358.     char *argv[],        /* pointer to array of argument strings */
  359.     char *envp[])        /* pointer to array of variable definitions */
  360. {
  361.     #pragma unused (envp)
  362.  
  363.     InitGraf((Ptr) &qd.thePort);
  364.     SetFScaleDisable(true);
  365.     InitCursor();
  366.     
  367.     if ( argc != 7 )
  368.     {
  369.         printf ("### Wrong Number of Parameters ###\n");
  370.         return 2;
  371.     }
  372.     
  373.     c.re            = atof(argv[1]);
  374.     c.im            = atof(argv[2]);
  375.     target.top        = atof(argv[3]);
  376.     target.left        = atof(argv[4]);
  377.     target.bottom    = atof(argv[5]);
  378.     target.right    = atof(argv[6]);
  379.  
  380.     x0 = (windowWidth - stepsX) / 2;
  381.     y0 = (windowHeight - stepsY) / 2;
  382.     
  383.     incX = (target.right - target.left) / stepsX;
  384.     incY = (target.bottom - target.top) / stepsY;
  385.  
  386.     alreadyDrawn = false;
  387.     
  388.     makeOffScreen();
  389.     makeWindow();
  390.     mainLoop();
  391.     cleanUp();
  392.  
  393.     return 0;
  394. }
  395.